#include "videotask.h"
#include "out_handler.h"

int64_t global_video_pkt_pts= AV_NOPTS_VALUE;

int our_get_buffer(struct AVCodecContext * c, AVFrame * pic)
{
    int ret = avcodec_default_get_buffer(c, pic);
    int64_t * pts = (int64_t *)av_malloc(sizeof(uint64_t));
    *pts =  global_video_pkt_pts;
    pic->opaque = pts;
    return ret;
}

void our_release_buffer(struct AVCodecContext * c, AVFrame * pic)
{
    if (pic)
        av_freep(&pic->opaque);

    avcodec_default_release_buffer(c, pic);
}

void VideoTask::appendVideoPacket(const AVPacket &aVpkt1)
{
    putq(std::string((char*)&aVpkt1,sizeof(AVPacket)));
}


VideoTask::VideoTask(Out_handler *ReceiveHandler , AVStream * pAVStream)
{

//    width   =   512;

//    height  =   288;

    width   =   pAVStream->codec->width;

    height  =   pAVStream->codec->height;


    m_ReceiveHandler = ReceiveHandler;

    m_pAVStream = pAVStream;


   // m_AVPacketList  = AVPacketList;

    video_clock = 0;

    pAVStream->codec->get_buffer = our_get_buffer;

    pAVStream->codec->release_buffer = our_release_buffer;

    img_convert_ctx = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height,AV_PIX_FMT_RGB24 , SWS_FAST_BILINEAR, NULL, NULL, NULL);


     pFrameRGB24 = avcodec_alloc_frame();

     int numBytesRGB = avpicture_get_size(AV_PIX_FMT_RGB24, width , height);

     bufferRGB = (uint8_t *)malloc(numBytesRGB * sizeof(uint8_t));

     avpicture_fill((AVPicture *)pFrameRGB24, bufferRGB, AV_PIX_FMT_RGB24,width , height);
}

VideoTask::~VideoTask()
{
    if(img_convert_ctx)
    {
        sws_freeContext(img_convert_ctx);

        img_convert_ctx = 0;
    }
    if(pFrameRGB24)
    {
        av_free(pFrameRGB24);

        pFrameRGB24 = 0;

    }
    if(bufferRGB)
    {
        free(bufferRGB);

        bufferRGB = 0;
    }
}
int VideoTask::svc()
{
    double pts;

    int len1, frameFinished;

   AVFrame * pFrame = avcodec_alloc_frame();

    AVPacket pktl;

    memset(&pktl,0,sizeof(AVPacket));

    std::string str ="";

    unsigned char *pBuffer = new unsigned char[width*height*3];


    while(getq(str))
    {
        if (str=="")
           break;

        memcpy(&pktl,str.data(),str.length());  //取出数据

        pts = 0;

        global_video_pkt_pts = pktl.pts;  //保存包的pts至 全局方便 avcodec_decode_video 分配帧是 赋值帧的pts

       len1 = avcodec_decode_video2(m_pAVStream->codec, pFrame, &frameFinished,&pktl);

        if ((pktl.dts == AV_NOPTS_VALUE) &&(pFrame->opaque) &&
                *(uint64_t *)pFrame->opaque != AV_NOPTS_VALUE)//???
        {
            pts = *(uint64_t *)pFrame->opaque;
        }
        else if (pktl.dts != AV_NOPTS_VALUE)
        {
             pts = pktl.dts;
        }
        else
        {
            pts = 0;
        }
        pts *= av_q2d(m_pAVStream->time_base);

        if (frameFinished)
        {
            pts = synchronize_video(pFrame, pts);
//            if (queue_picture(is, pFrame, pts) < 0)//会阻塞 产生一帧 等待绘制后 解码下一包
//            {
//                break;
//            }
            //先不判断长度
            sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, m_pAVStream->codec->height, pFrameRGB24->data, pFrameRGB24->linesize);
            memset(pBuffer,0,width*height*3);
            memcpy(pBuffer,pFrameRGB24->data[0],pFrameRGB24->linesize[0]*m_pAVStream->codec->height);

            if(m_ReceiveHandler)
                m_ReceiveHandler->receive_handler(pBuffer,pFrameRGB24->linesize[0]*m_pAVStream->codec->height,pts);
        }

        av_free_packet(&pktl);
    }

    delete []pBuffer;

    return 1;
}

double VideoTask::synchronize_video(AVFrame * src_frame, double pts)
{
    double frame_delay;

    if (pts != 0)
    {
        // if we have pts, set video clock to it
        video_clock = pts;
    }
    else
    {
        // if we aren't given a pts, set it to the clock
        pts = video_clock;
    }
    // update the video clock
    frame_delay = av_q2d(m_pAVStream->codec->time_base);
    // if we are repeating a frame, adjust clock accordingly
    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);

    video_clock += frame_delay;

    return pts;
}
int VideoTask::close()
{
    std::string str("");
    int nthread  =thr_count();

    for (int i =0 ;i<nthread ;i++)
        putq(str);

    wait();
    return 0;
}
